package com.darkflame.client.semantic;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import com.darkflame.client.SuperSimpleSemantics;
import com.darkflame.client.interfaces.SSSGenericFileManager.FileCallbackError;
import com.darkflame.client.interfaces.SSSGenericFileManager.FileCallbackRunnable;
import com.google.common.collect.ArrayListMultimap;

//import com.google.gwt.user.client.rpc.AsyncCallback;

public class SssStatementList {
	

	static Logger Log = Logger.getLogger("sss.SssStatementList");
	//public ArrayList<SssStatement> statements = new ArrayList<SssStatement>();
	
	public ArrayListMultimap<String,SssStatement> newstatements = ArrayListMultimap.create();
	
	enum StatementFileType {
		N3,SSS
	}
	
	public SssStatementList (){
		
	}
	
	/** change to list later **/
	public ArrayList<SssStatement> getStatements(){
		
		ArrayList<SssStatement> statements = new ArrayList(newstatements.values());
		
		
		return statements;
		
		
	}
	
	//public void LoadStatementsFromFile( final String url, final AsyncCallback<String> calledWhenDone ){
		//if (url.endsWith(".n3")){
			
	//		LoadStatementsFromN3File(url, calledWhenDone);
			
	//	}
	//	if (url.endsWith(".sss")){
			
		//	LoadStatementsFromSSSFile(url, calledWhenDone);
			
		//}
//	}
	/** with SSS files the precedent and object are specified in advance.
	 * The file just contains things with this property **/
	public void LoadStatementsFromSSSFile( final String url,final String precident, final String value, final LoadingCallback calledWhenDone ){
		
		//set type
		StatementFileType type = StatementFileType.SSS;
			
		//
		FileCallbackRunnable onResponse = new FileCallbackRunnable(){

			@Override
			public void run(final String responseData, int responseCode) { 
				//Log.info("file found " + response.getText());
				
				//process file
				
				//This default is wrong. probably.
				String ns = url.substring(0, url.lastIndexOf("/"))+"/DefaultOntology.n3";
				LoadStatements(responseData, StatementFileType.SSS, precident, value, ns);
																	
				//send the "done" message
				calledWhenDone.onSuccess("FileLoaded");
			}
			
		};
		
		FileCallbackError onError = new FileCallbackError(){
			@Override
			public void run(String errorData, Throwable exception) {
				Log.info("getting file list "
						+ url + " failed");
			}
		
		};
		

		SuperSimpleSemantics.fileManager.getText(url,
				onResponse,
				onError,
				false);
		/*
		
		final RequestBuilder getPropertyFile = new RequestBuilder(
				RequestBuilder.GET, url);

		try {
			getPropertyFile.sendRequest("", new RequestCallback() {
				public void onError(Request request, Throwable exception) {
					Log.info("getting file list "
							+ getPropertyFile.getUrl() + " failed");
				}

				public void onResponseReceived(Request request,
						Response response) {
					
					//Log.info("file found " + response.getText());
					
					//process file
					String ns = url.substring(0, url.lastIndexOf("/"))+"/DefaultOntology.n3";
					LoadStatements(response.getText(), StatementFileType.SSS, precident, value, ns);
																		
					//send the "done" message
					calledWhenDone.onSuccess("FileLoaded");
					
				}
			});
			
		} catch (RequestException ex) {

			Log.info("get request list failed:" + ex.getMessage());
			
		}*/
		
		
	}
	
	public void LoadStatementsFromN3File( final String url, final LoadingCallback calledWhenDone ){
		
		
		//set type
		StatementFileType type = StatementFileType.N3;
		
		
		FileCallbackRunnable onResponse = new FileCallbackRunnable(){

			@Override
			public void run(final String responseData, int responseCode) { 
				
				//process file
				LoadStatements(responseData, StatementFileType.N3);
							
				//send the "done" message
				calledWhenDone.onSuccess("FileLoaded");
			}
		
		};
		
		FileCallbackError onError = new FileCallbackError(){
			@Override
			public void run(String errorData, Throwable exception) {
				Log.info("getting file list "
						+ url + " failed");
			}
		
		};
		
		
		SuperSimpleSemantics.fileManager.getText(url,
				onResponse,
				onError,
				false);
		
		/*
		
		final RequestBuilder getPropertyFile = new RequestBuilder(
				RequestBuilder.GET, url);

		try {
			getPropertyFile.sendRequest("", new RequestCallback() {
				public void onError(Request request, Throwable exception) {
					Log.info("getting file list "
							+ getPropertyFile.getUrl() + " failed");
				}

				public void onResponseReceived(Request request,
						Response response) {
					
					//Log.info("file found " + response.getText());
					
					//process file
					LoadStatements(response.getText(), StatementFileType.N3);
								
					//send the "done" message
					calledWhenDone.onSuccess("FileLoaded");

				}
			});
			
		} catch (RequestException ex) {

			Log.info("get request list failed:" + ex.getMessage());
			
		}
		
		*/
	}
	
	protected void LoadStatements(String text, StatementFileType filetype) {
		
		LoadStatements(text,filetype,null,null,null);
		
	}
	
	/** load statements from file. Remember, SSS type has to have pre/val**/
	protected void LoadStatements(String text, StatementFileType filetype, String pre, String val, String NS) {
		
		//split to lines
		String lines[] = text.split("\r?\n|\r");
				
		String previousline = ""; //we track the previous line so labels be added on the line following a node
		//eg
		// GrannySmithApple;
		// "Granny Smith Apple".
		// 
		// Previous lines should only be stored if the line ended in a ; and theres none stored already
	    // They should be cleared after a . or a line without anything at the end
		
		//loop over lines
		int i=0;
		while(i<lines.length)
		{
			String currentLine = lines[i];
			i++;
			
			//if empty continue
			if (currentLine.isEmpty()){
				continue;
			}
			
			//if its a prefix
			if (currentLine.startsWith("@prefix")){
				
				currentLine = currentLine.replaceAll("@prefix ", "");				
				String[] linebits = currentLine.split("<");
				String prefix = linebits[0].trim();
				String uri = linebits[1].trim();
				//find and crop to before ending >
				int endsat  = uri.indexOf(">");
				uri=uri.substring(0, endsat);
				Log.info("loadstatements_loading prefixs from line p-:"+prefix+" u:"+uri);				
				RawQueryUtilities.addPrefix(uri, prefix);
				
			} else {
				
				//process line based on format				
				if (filetype == StatementFileType.N3){ //Doubt this fully works
					addStatementFromN3Line(currentLine);
				}
				
				if (filetype == StatementFileType.SSS){ //this should
					addStatementFromSSSLine(currentLine, pre ,val, NS);	
				}
				
				//update previous line if needed
				if (currentLine.endsWith(";") && previousline == ""){
					previousline = currentLine;
				}
				//clear if not a ; at the end of the current line
				//NOTE: really newlines following ; should either end by a . or a ;
				//but we assume anything but a ; means clear (ie, the next line is not associated with the last)
				if (currentLine.endsWith(";")){
					previousline="";				
				}
				
				
				
				
			}
			
			
			
			
		}
		
	
		
	}
	
	
	protected void addStatementFromSSSLine(String line, String Pre, String Val,String SourceNS){
		
	Log.info("adding statement from line:"+line);
		
		String[] linebits = line.split(" ");
		
		//loop over adding them correctly (we don't assume single spaces separate the s p o)
		int i=0;
		int fragment = 0;
		
		String subject = "";
		String predicate = RawQueryUtilities.getURI(Pre);
		String object    = RawQueryUtilities.getURI(Val);
				
		//Standardize the URIs if possible
		
	//	predicate = SssURIsetStorage.getPrimaryUriForLabel(predicate);
	//	object = SssURIsetStorage.getPrimaryUriForLabel(object);
		String linebit ="";
		boolean quoteOpen = false;
		while (i<linebits.length){
			

			linebit = (linebit+" "+linebits[i]).trim();
			i++;
			if (linebit.startsWith("\"")&& !quoteOpen){										
				//ensure it doesnt also end the quote before flagging quote as open
				if (!linebit.substring(1).contains("\"")){
				quoteOpen = true;
				}
				
			} else if (linebit.substring(1).contains("\"")&& quoteOpen){
				Log.info("full quoted line:="+linebit);
				quoteOpen =false;
			}
			
			if (quoteOpen){				
				continue;
			}
			if (linebit.isEmpty()){
				continue;
			}
			
			if (fragment==0){
				subject=linebit.trim();
				//expand uri if known
				subject = RawQueryUtilities.getURI(subject);
				//add url to subject if it has none
				if (!(subject.startsWith("http:")||subject.startsWith("https:"))){
				subject = SourceNS +"#"+ subject;
				
				//Add label<>URI equilivency to storage, if its a new one then create a new SameAS statement
				
				
				}
				
				if (!(predicate.startsWith("http:")||predicate.startsWith("https:"))){
					//strip quotes
					predicate = predicate.replaceAll("\"", "");
					predicate = SourceNS +"#"+ predicate;
					
					//Add label<>URI equilivency to storage, if its a new one then create a new SameAS statement
					
				}
				
			} 
			fragment++;
			linebit="";
		}
		
		

		addStatement(subject, predicate, object);
		
		//SssStatement newstatment = new SssStatement(subject, predicate, object);
		//Log.info("Adding statement:"+newstatment.asString());
		//statements.add(newstatment);
		
		
	}
	
	
	protected void addStatementFromN3Line(String line){
		
		Log.info("adding statement from line:"+line);
		
		String[] linebits = line.split(" ");
		
		//loop over adding them correctly (we dont assume single spaces seperate the s p o)
		int i=0;
		int fragment = 0;
		String subject = "";
		String predicate = "";
		String object = "";
			
		while (i<linebits.length){
			
			String linebit = linebits[i];
			i++;
			
			if (linebit.isEmpty()){
				continue;
			}
			
			if (fragment==0){
				subject=linebit.trim();
				//expand uri if known
				
			} 
			if (fragment==1){
				predicate=linebit.trim();
				
			} 
			if (fragment==2){
				object=linebit.trim();
				
				break;
			} 
			fragment++;
			
		}
		
		addStatement(subject, predicate, object);
		
		
		
	}
	
	public void addStatement(String subject, String predicate, String value){
				
		subject = RawQueryUtilities.getURI(subject);
		predicate = RawQueryUtilities.getURI(predicate);
		value = RawQueryUtilities.getURI(value);
		
		SssStatement newstatment = new SssStatement(subject, predicate, value);
		
		Log.info("Adding statement:"+newstatment.asString()+" for key "+predicate+"_&_"+value);
		
		//statements.add(newstatment);
		
		newstatements.put(predicate+"_&_"+value,newstatment);
		
	}
	
	
	public boolean containsStatement(SssStatement statement){
		
	    boolean contains=false;
		
	    String pre = statement.precident;
	    String val = statement.value;
	
	    contains = newstatements.containsKey(pre+"_&_"+val);
	    /*
		Iterator<SssStatement> sit = statements.iterator();
		
		while (sit.hasNext()){
			
			SssStatement Current = sit.next();
			
			//Log.debug("___comparing to precident:"+Current.precident+" ");
			//Log.debug("___comparing to value:"+Current.value+" ");
			
			
			if (  Current.precident.equals(pre) && Current.value.equals(val) ){
				contains=true;
				break;
			}
			
			
		}
*/
		
		return contains;
	}
	
	
	
	public ArrayList<String> getURIsThatMatch(String pre,String val){
		
		//we search for the prefixed version or the full one
		String pre_short = RawQueryUtilities.getPrefix(pre);
		String val_short = RawQueryUtilities.getPrefix(val);
		
		//long version
		//pre = RawQueryUtilities.getURI(pre_short);
		//val = RawQueryUtilities.getURI(val_short);
		
		//Disabled the search for long uris for now.
		
		
		//Log.info("______looking for (long):"+pre+ "+"+val);
	//	Log.info("______looking for (short):"+pre_short+ "+"+val_short);
		
		//Log.info("_____in array sized:"+newstatements.size());
		/*
		String searchstring = pre+"_&_"+val;
		
		
		List<SssStatement> results1 = newstatements.get(searchstring);
		Log.info("_found:"+results1.size());
				*/
		
		String searchstring2 = pre_short+"_&_"+val_short;

		Log.info("_____searching for:"+searchstring2);
		
		//Log.info("_____searching for:"+searchstring2);
		
		List<SssStatement> results2 = newstatements.get(searchstring2);
		//Log.info("_found:"+results2.size());
		
		//results1.addAll(results2);
		
		ArrayList<String> results = new ArrayList<String>();
		
		Iterator<SssStatement> rit = results2.iterator();
		
		Log.info("rit size="+results2.size());
				
		while (rit.hasNext()) {
			
			String URI = rit.next().subject;
			if (!results.contains(URI)){
			results.add(URI);
			}
		} 
		
		Log.info("result size="+results.size());
		
			
		
		/*
		ArrayList<String> results = new ArrayList<String>();
		
		Iterator<SssStatement> sit = statements.iterator();
		
		while (sit.hasNext()){
			
			SssStatement Current = sit.next();
			
			Log.debug("_____comparing to precident:"+Current.precident+" ");
			Log.debug("_____comparing to value:"+Current.value+" ");
			
			
			if ( ( Current.precident.equals(pre)||Current.precident.equals(pre_short)) && (Current.value.equals(val)||Current.value.equals(val_short)) ){
				
				//add if not there
				if (!results.contains(Current.subject)){
				results.add(Current.subject);
				Log.info("FOUND:"+Current.subject);
				}
			}
			
			
		}*/
		return results;
	}
}
